// Copyright (c) 2025 Inochi Amaoto

/* SPDX-License-Identifier: GPL-2.0 */

#ifndef __VIRTIO_VAPP_VIO_H__
#define __VIRTIO_VAPP_VIO_H__

#include "virtio-vapp.h"
#include "vio-entity.h"
#include "vio-mm.h"

static void vio_vapp_context_init(struct vio_vapp_context* ctx, u64 id)
{
  ctx->id = id;
  vio_vapp_notify_queue_init(&ctx->queue);
  vapp_entity_tree_init(&ctx->req);
  vapp_entity_tree_init(&ctx->rsp);
  vio_mmap_entity_tree_init(&ctx->mtree);
}

static struct vio_vapp_context* vio_vapp_context_alloc(u64 id)
{
  struct vio_vapp_context* ctx = kmalloc(sizeof(struct vio_vapp_context), GFP_KERNEL);

  if (!ctx)
    return ERR_PTR(-ENOMEM);

  vio_vapp_context_init(ctx, id);
  return ctx;
}

static void vio_vapp_context_deinit(struct vio_vapp_context* ctx)
{
  vio_vapp_notify_queue_destroy(&ctx->queue);
  vapp_entity_tree_destroy(&ctx->req);
  vapp_entity_tree_destroy(&ctx->rsp);
  vio_mmap_entity_tree_destroy(&ctx->mtree);
}

static void vio_vapp_context_free(struct vio_vapp_context* ctx)
{
  kvfree(ctx);
}


__maybe_unused
static void virtio_vapp_dev_start_work(struct virtio_vapp_dev* vapp)
{
  for (size_t i = 0; i < vapp->config.multiqueues; i++)
    virtio_vapp_queue_work(&vapp->ddtqs[i].send_work);
}

__maybe_unused
static int vio_vapp_entity_send_packet(struct vio_vapp_entity* entity, struct vio_vapp_entity_tree* tree)
{
  struct virtio_vapp_dev* vapp;
  struct vapp_send_data_packet* packets[VIO_VAPP_ENTITY_PKTS];
  int nr, i;

  pr_info("enter send packet\n");
  pr_info("packet: entity->alloc: %llu\n", entity->alloc);

  rcu_read_lock();
  vapp = virtio_vapp_get_dev_rcu();
  if (!vapp) {
    nr = -ENODEV;
    goto out;
  }

  nr = vio_vapp_entity_split_packet(entity, tree, packets);
  if (nr < 0)
    goto out;

  pr_info("packet: need to send %d packet\n", nr);

  for (i = 0; i < nr; i++)
    vapp_send_queue_add_tail(&vapp->dqueue, &packets[i]->node);

  virtio_vapp_dev_start_work(vapp);

  rcu_read_unlock();
  return 0;

 out:
  rcu_read_unlock();
  return nr;
}

#endif // ! __VIRTIO_VAPP_VIO_H__
